use crate::lexer_mod::token_type_enum::TokenType;
use std::collections::HashSet;
use token_type_enum::{Compared, KeyWord, Operator};
use crate::lexer_mod::token::Token;

pub mod token;
pub mod token_type_enum;
const KEYWORDS: [&str; 13] = [
    "func", "class", "if", "true", "false", "null", "else", "return", "while", "for", "goto",
    "continue","_"
];
/// 类型关键字
const TYPEWORDS: [&str; 7] = ["int", "string", "float", "var", "object", "bool", "none"];
pub struct ErrInfo {
    //IDE错误信息显示?
    pub line: i32,
    pub row: i32,
    //控制台输出
    pub text: String,
}

/// line，row，用于报错追踪.

pub struct Lexer {
    pub pos: usize,
    pub text: Vec<char>,
    pub tokens: Vec<token::Token>,
    pub errors: Vec<ErrInfo>,

    key_words: HashSet<String>,
    type_words: HashSet<String>,
    line: i32,
    //当前行的第几项.
    row: i32,
}
impl Lexer {
    pub fn new(str: String) -> Lexer {
        let mut key_words: HashSet<String> = HashSet::new();
        for key in KEYWORDS {
            key_words.insert(key.to_string());
        }

        let mut type_words: HashSet<String> = HashSet::new();
        for key in TYPEWORDS {
            type_words.insert(key.to_string());
        }

        Lexer {
            pos: 0,
            text: str.chars().collect(),
            key_words,
            type_words,
            tokens: vec![],
            errors: vec![],
            line: 0,
            row: 0,
        }
    }
    pub fn read_token(&mut self) {
        //第几行
        while self.pos < self.text.len() {
            let char = self.text[self.pos];
            let mut move_next = 1;

            let result_token_type = match char {
                '{' => Some(TokenType::BlockBegin),
                '}' => Some(TokenType::BlockEnd),
                '[' => Some(TokenType::ArrayBegin),
                ']' => Some(TokenType::ArrayEnd),
                '(' => Some(TokenType::FuncBegin),
                ')' => Some(TokenType::FuncEnd),
                ';' => Some(TokenType::Semicolon),
                ':' => Some(TokenType::Colon),
                ',' => Some(TokenType::And),
                '+' => Some(TokenType::Operator(Operator::Add)),
                '-' => Some(TokenType::Operator(Operator::Sub)),
                '*' => Some(TokenType::Operator(Operator::Mul)),
                '.' => Some(TokenType::Dot),
                '/' => {
                    if self.pos + 1 < self.text.len() {
                        let next = self.text[self.pos + 1];
                        if next == '/' || next == '*' {
                            let offset = self.read_comments();
                            self.pos += offset;
                            self.row += offset as i32;
                            continue;
                        }
                    }
                    Some(TokenType::Operator(Operator::Div))
                }
                ' ' => {
                    self.pos += 1;
                    self.row += 1;
                    continue;
                }
                '\n' => {
                    self.pos += 1;
                    self.row = 0;
                    self.line += 1;
                    continue;
                }
                '!' => {
                    let mut type_result: TokenType = TokenType::Operator(Operator::Negate);
                    if self.pos + 1 < self.text.len() {
                        let next_char = self.text[self.pos + 1];
                        if next_char == '=' {
                            move_next = 2;
                            type_result = TokenType::Compared(Compared::NotEquals);
                        }
                    }
                    Some(type_result)
                }
                '=' => {
                    let mut type_result: TokenType = TokenType::Operator(Operator::Assignment);
                    if self.pos + 1 < self.text.len() {
                        let next_char = self.text[self.pos + 1];
                        if next_char == '=' {
                            move_next = 2;
                            type_result = TokenType::Compared(Compared::Equals);
                        }
                    }
                    Some(type_result)
                }
                '>' => {
                    let mut type_result: TokenType = TokenType::Compared(Compared::GreaterThan);
                    if self.pos + 1 < self.text.len() {
                        let next_char = self.text[self.pos + 1];
                        if next_char == '>' {
                            move_next = 2;
                            type_result = TokenType::Operator(Operator::ShiftRight);
                        }
                        if next_char == '=' {
                            move_next = 2;
                            type_result = TokenType::Compared(Compared::GreaterThanOrEquals);
                        }
                    }
                    Some(type_result)
                }
                '<' => {
                    let mut type_result: TokenType = TokenType::Compared(Compared::LessThan);
                    if self.pos + 1 < self.text.len() {
                        let next_char = self.text[self.pos + 1];
                        if next_char == '<' {
                            move_next = 2;
                            type_result = TokenType::Operator(Operator::ShiftLeft);
                        }
                        if next_char == '=' {
                            move_next = 2;
                            type_result = TokenType::Compared(Compared::LessThanOrEquals);
                        }
                    }
                    Some(type_result)
                }
                '\"' => {
                    self.pos += 1;
                    self.row += 1;
                    let offset = self.read_const_string();
                    self.pos += offset;
                    self.row += offset as i32;
                    continue;
                }

                _ => {
                    if char.is_ascii_digit() {
                        let offset = self.read_const_num();
                        self.pos += offset;
                        self.row += offset as i32;
                        continue;
                    }
                    None
                }
            };

            match result_token_type {
                None => {
                    //推断可能为标识符,如果非标识符offset就会为0，不会移动。
                    let offset = self.read_identifier();
                    self.pos += offset;
                    self.row += offset as i32;
                }
                Some(result) => {
                    self.push_token(result);
                    self.pos += move_next;
                    self.row += move_next as i32;
                }
            }
        }
    }
    ///读取注释
    fn read_comments(&mut self) -> usize {
        let mut value: String = String::new();
        let mut offset: usize = 0;
        //是否为多行注释
        let mut mut_line = false;
        //是否为文档注释
        let mut is_doc = false;
        //   /*
        if self.pos + 1 < self.text.len() && self.text[self.pos + 1] == '*' {
            mut_line = true;
            offset += 1;
        } else if self.pos + 2 < self.text.len()
            && self.text[self.pos + 1] == '/'
            && self.text[self.pos + 2] == '/'
        {
            //   /// 文档
            is_doc = true;
            offset += 3;
        }
        //
        while self.pos + offset < self.text.len() {
            let current_char = self.text[self.pos + offset];
            if !mut_line && current_char == '\n' {
                offset += 2;
                break;
            } else if mut_line {
                if self.pos + offset + 1 < self.text.len() {
                    let next = self.text[self.pos + offset + 1];
                    if current_char == '*' && next == '/' {
                        offset += 2;
                        break;
                    }
                }
            }

            if is_doc {
                if current_char != '\n' {
                    value.push(current_char)
                }
            }
            offset += 1;
        }

        if is_doc && !value.is_empty() {
            self.push_token(TokenType::CommentDoc(value));
        }

        return offset;
    }

    fn read_const_num(&mut self) -> usize {
        let mut value: String = String::new();
        let mut offset: usize = 0;
        let mut has_dot = false;
        while self.pos + offset < self.text.len() {
            let current_char = self.text[self.pos + offset];
            if current_char == '.' {
                if has_dot {
                    break;
                } else {
                    if self.pos + offset + 1 < self.text.len() {
                        let next = self.text[self.pos + offset + 1];
                        if next.is_ascii_digit() {
                            //只允许123.[0,9]
                            value.push(current_char);
                            has_dot = true;
                            offset += 1;
                            continue;
                        } else {
                            //处理类似于 123.xxx();的操作
                            break;
                        }
                    }
                }
            }

            // if (!lexer_mod::is_id_continue(current_char)) {
            //     break;
            // }

            if current_char.is_ascii_digit() {
                value.push(current_char);
                offset += 1;
                continue;
                //支持 123_456_789=> 123456789的写法
            } else if current_char == '_' {
                if self.pos + offset + 1 < self.text.len() {
                    let next = self.text[self.pos + offset + 1];
                    if !next.is_ascii_digit() {
                        self.push_err(format!(
                            "\"{}{}\n{}↑↑↑\n下划线不能以非数字结尾",
                            value,
                            current_char,
                            " ".repeat(value.len())
                        ));
                    }
                } else {
                    self.push_err(format!(
                        "\"{}{}\n{}↑↑↑\n数字不能以下划线结尾",
                        value,
                        current_char,
                        " ".repeat(value.len())
                    ));
                }
                offset += 1;
                continue;
            } else {
                //是文本
                if Lexer::is_id_continue(current_char) {
                    self.push_err(format!(
                        "\"{}{}\n{}↑↑↑\n标识符不能以数字开头",
                        value,
                        current_char,
                        " ".repeat(value.len())
                    ));
                }

                break;
            }
        }

        if value.is_empty() {
            return offset;
        }

        if value.contains(".") {
            self.push_token(TokenType::ConstFloat(
                value.parse::<f32>().expect("浮点数解析失败"),
            ));
        } else {
            let num: i128 = value.parse::<i128>().expect("整数解析失败");
            if num >= i64::MAX as i128 {
                self.push_token(TokenType::ConstLongLong(num));
                return offset;
            }

            if num >= i32::MAX as i128 {
                self.push_token(TokenType::ConstLong(num as i64));
                return offset;
            }
            self.push_token(TokenType::ConstNumber(num as i32));
        }

        offset
    }

    ///读取 "string"
    /// return: 字符偏移量
    fn read_const_string(&mut self) -> usize {
        let mut value: String = String::new();
        let mut close = false;
        let mut offset: usize = 0;
        while self.pos + offset < self.text.len() {
            let char = self.text[self.pos + offset];
            offset += 1;

            if char == '\"' {
                close = true;
                break;
            } else {
                //有限转义支持
                if char == '\\' && self.pos + offset < self.text.len() {
                    let next = self.text[self.pos + offset];
                    //非转义符号不转义
                    let mut str = String::new();
                    str.push(char);
                    str.push(next);

                    let result = match next {
                        'n' => "\n",
                        'r' => "\r",
                        't' => "\t",
                        '\\' => "\\",
                        '\"' => "\"",
                        _ => str.as_str(),
                    };
                    value.push_str(result);
                } else {
                    value.push(char);
                }
            }
        }

        if !close {
            self.push_err(format!(
                "\"{}\n{}↑↑↑\n字符串未闭合",
                value,
                " ".repeat(value.len())
            ));
        }

        if value.is_empty() {
            return offset;
        }
        self.push_token(TokenType::ConstString(value));

        return offset;
    }

    ///读取没有被双引号包起来的值,如果是关键字则创建关键字token。
    /// return: 字符偏移量
    fn read_identifier(&mut self) -> usize {
        //只要起始下标
        let mut Value: String = String::new();
        let mut offset = 0;
        while self.pos + offset < self.text.len() {
            let char = self.text[self.pos + offset];
            if Lexer::is_id_continue(char) {
                offset += 1;
                Value.push(char);
            } else {
                break;
            }
        }
        if Value.is_empty() {
            return offset;
        }
        //类型关键词token
        if self.type_words.contains(&Value) {
            self.push_token(TokenType::VarType(Value));
            return offset;
        }

        //其他关键词token
        if self.key_words.contains(&Value) {
            let result = match Value.to_lowercase().as_str() {
                "_"=>Some(TokenType::ConstDeduceNum),
                "class" => Some(TokenType::KeyWord(KeyWord::Class)),
                "func" => Some(TokenType::KeyWord(KeyWord::Func)),
                "true" => Some(TokenType::ConstBool(true)),
                "false" => Some(TokenType::ConstBool(false)),
                "null" => Some(TokenType::KeyWord(KeyWord::Null)),
                "if" => Some(TokenType::KeyWord(KeyWord::If)),
                "else" => Some(TokenType::KeyWord(KeyWord::Else)),
                "return" => Some(TokenType::KeyWord(KeyWord::Return)),
                "while" => Some(TokenType::KeyWord(KeyWord::While)),
                "for" => Some(TokenType::KeyWord(KeyWord::For)),
                "goto" => Some(TokenType::KeyWord(KeyWord::Goto)),
                "continue" => Some(TokenType::KeyWord(KeyWord::Continue)),
                _ => None,
            };
            match result {
                None => {
                    //这里属于开发时错误，不是解析式错误。
                    println!(
                        "解析失败,定义了关键字,但是没有处理？ {} at (line: {},row:{})",
                        Value, self.line, self.row
                    );
                }
                Some(result) => {
                    self.push_token(result);
                }
            }
        } else {
            self.push_token(TokenType::Identifier(Value));
        }
        return offset;
    }

    fn push_token(&mut self, token_type: TokenType) {
        self.tokens.push(token::Token {
            line: self.line,
            row: self.row,
            token_type: token_type,
        });
    }
    fn push_err(&mut self, text: String) {
        self.errors.push(ErrInfo {
            line: self.line,
            row: self.row,
            text,
        });
    }
    //token流合法检查
    pub fn is_legal(&mut self) -> bool {
        if self.errors.len() > 0 {
            for err in &self.errors {
                println!("token解析时错误:(line:{},row:{}) \n{}\n",err.line,err.row, err.text)
            }
            return false;
        }
        true
    }
    fn is_id_continue(c: char) -> bool {
        c.is_alphanumeric() || c == '_'
    }

    pub fn print_tokens(&self) {
        for token in &self.tokens {
            println!("{}", token)
        }
    }
}
